#include "formula_sytanmic.h"

DTInterval Formula::calresult(DTInterval x, DTInterval y) {
    for (int i = 0; i < czan; ++i) {
        operators.push(zan[i]);
    }
    //cout << operators.top() << endl;
    // calculate
    while (operators.size()) {
        if ('0' <= operators.top()[0] && operators.top()[0] <= '9') {
            result.push(intervalFromReals<DTInterval>(stod(operators.top()), stod(operators.top())));
            operators.pop();
            continue;
        }
        else if (operators.top() == "x") {
            result.push(x);
            operators.pop();
            continue;
        }
        else if (operators.top() == "y") {
            result.push(y);
            operators.pop();
            continue;
        }
        else if (operators.top() == "+") {
                operators.pop();
                DTInterval b(result.top());
                result.pop();
                DTInterval a(result.top());
                result.pop();
                result.push(a+b);
        }
        else if (operators.top() == "-") {
            operators.pop();
            DTInterval b(result.top());
            result.pop();
            DTInterval a(result.top());
            result.pop();
            result.push(a-b);
        }
        else if (operators.top() == "*") {
            operators.pop();
            DTInterval b(result.top());
            result.pop();
            DTInterval a(result.top());
            result.pop();
            result.push(a*b);
        }
        else if (operators.top() == "/") {
            operators.pop();
            DTInterval b(result.top());
            result.pop();
            DTInterval a(result.top());
            result.pop();
            result.push(a/b);
        }
        else if (operators.top() == "sin") {
            operators.pop();
            DTInterval a(result.top());
            result.pop();
            result.push(a.isin());
        }
        else if (operators.top() == "cos") {
            operators.pop();
            DTInterval a(result.top());
            result.pop();
            result.push(a.icos());
        }
        else if (operators.top() == "tan") {
            operators.pop();
            DTInterval a(result.top());
            result.pop();
            result.push(a.itan());
        }
        else if (operators.top() == "log") {
            operators.pop();
            DTInterval a(result.top());
            result.pop();
            result.push(a.ilog());
        }
        else if (operators.top() == "^") {
            operators.pop();
            int b = (int)(result.top().unsafeA());
            result.pop();
            DTInterval a(result.top());
            result.pop();
            result.push(a^b);
        }
        else {
            cout << "something got wrong." << endl;
        }
    }
    DTInterval res(result.top());
    result.pop();
    return res;
}

void Formula::initNUm(string expres) {
    for (uint32_t i = 0; i < expres.length(); ++i) {
        if (('0' <= expres[i] && expres[i] <= '9') || expres[i] == '.' || expres[i] == 'x' || expres[i] == 'y') {
            pre_num += expres[i];
            continue;
        }
        else {
            pre_operator += expres[i];
            if (pre_operator == "s") {
                i += 2;
                pre_operator = "sin";
            }
            else if (pre_operator == "c") {
                i += 2;
                pre_operator = "cos";
            }
            else if (pre_operator == "t") {
                i += 2;
                pre_operator = "tan";
            }
            else if (pre_operator == "l") {
                i += 2;
                pre_operator = "log";
            }
        }

        // num
        if (pre_num != "") {
            nums.push(pre_num);
            pre_num = "";
        }

        // operators
        if (pre_operator != "") {
            if (pre_operator == "(") {
                operators.push(pre_operator);
            }
            else if (pre_operator == ")") {
                while (operators.size()) {
                    if (operators.top() == "(") {
                        operators.pop();
                        break;
                    }
                    nums.push(operators.top());
                    operators.pop();
                }
            }
            else {  // other operator
                if (operators.size() == 0 || operators.top() == "(" ||
                    operators_priority[pre_operator] >= operators_priority[operators.top()])
                    operators.push(pre_operator);
                else {
                    while (operators.size() && operators_priority[pre_operator] < operators_priority[operators.top()]) {
                        nums.push(operators.top());
                        operators.pop();
                    }
                    operators.push(pre_operator);
                }
            }

            pre_operator = "";
        }
    }

    // the last num
    if (pre_num != "") {
        nums.push(pre_num);
    }

    // the last operators
    while (operators.size()) {
        nums.push(operators.top());
        operators.pop();
    }

    // -------------------------------- //
    // restore in operators
    while (nums.size()) {
        zan[czan++] = nums.top();
        nums.pop();
    }
}

Formula::Formula() {
    operators_priority["+"] = 0;
    operators_priority["-"] = 0;
    operators_priority["*"] = 1;
    operators_priority["/"] = 1;
    operators_priority["sin"] = 2;
    operators_priority["cos"] = 2;
    operators_priority["tan"] = 2;
    operators_priority["log"] = 2;
    operators_priority["^"] = 3;
}


